{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "e0151427",
   "metadata": {},
   "outputs": [],
   "source": [
    "deployment = \"gpt4\"\n",
    "model = \"gpt-4\"\n",
    "embedding_deployment = \"embedding\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "a2c0e366",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Requirement already satisfied: chromadb in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (0.4.7)\n",
      "Requirement already satisfied: requests>=2.28 in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from chromadb) (2.31.0)\n",
      "Requirement already satisfied: pydantic<2.0,>=1.9 in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from chromadb) (1.10.12)\n",
      "Requirement already satisfied: chroma-hnswlib==0.7.2 in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from chromadb) (0.7.2)\n",
      "Requirement already satisfied: fastapi<0.100.0,>=0.95.2 in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from chromadb) (0.99.1)\n",
      "Requirement already satisfied: uvicorn[standard]>=0.18.3 in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from chromadb) (0.23.2)\n",
      "Requirement already satisfied: numpy>=1.21.6 in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from chromadb) (1.24.3)\n",
      "Requirement already satisfied: posthog>=2.4.0 in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from chromadb) (3.0.2)\n",
      "Requirement already satisfied: typing-extensions>=4.5.0 in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from chromadb) (4.7.1)\n",
      "Requirement already satisfied: pulsar-client>=3.1.0 in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from chromadb) (3.2.0)\n",
      "Requirement already satisfied: onnxruntime>=1.14.1 in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from chromadb) (1.15.1)\n",
      "Requirement already satisfied: tokenizers>=0.13.2 in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from chromadb) (0.13.2)\n",
      "Requirement already satisfied: pypika>=0.48.9 in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from chromadb) (0.48.9)\n",
      "Requirement already satisfied: tqdm>=4.65.0 in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from chromadb) (4.65.0)\n",
      "Requirement already satisfied: overrides>=7.3.1 in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from chromadb) (7.4.0)\n",
      "Requirement already satisfied: importlib-resources in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from chromadb) (6.0.1)\n",
      "Requirement already satisfied: bcrypt>=4.0.1 in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from chromadb) (4.0.1)\n",
      "Requirement already satisfied: starlette<0.28.0,>=0.27.0 in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from fastapi<0.100.0,>=0.95.2->chromadb) (0.27.0)\n",
      "Requirement already satisfied: coloredlogs in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from onnxruntime>=1.14.1->chromadb) (15.0.1)\n",
      "Requirement already satisfied: flatbuffers in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from onnxruntime>=1.14.1->chromadb) (23.5.26)\n",
      "Requirement already satisfied: packaging in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from onnxruntime>=1.14.1->chromadb) (23.0)\n",
      "Requirement already satisfied: protobuf in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from onnxruntime>=1.14.1->chromadb) (4.24.1)\n",
      "Requirement already satisfied: sympy in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from onnxruntime>=1.14.1->chromadb) (1.11.1)\n",
      "Requirement already satisfied: six>=1.5 in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from posthog>=2.4.0->chromadb) (1.16.0)\n",
      "Requirement already satisfied: monotonic>=1.5 in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from posthog>=2.4.0->chromadb) (1.6)\n",
      "Requirement already satisfied: backoff>=1.10.0 in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from posthog>=2.4.0->chromadb) (2.2.1)\n",
      "Requirement already satisfied: python-dateutil>2.1 in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from posthog>=2.4.0->chromadb) (2.8.2)\n",
      "Requirement already satisfied: certifi in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from pulsar-client>=3.1.0->chromadb) (2023.7.22)\n",
      "Requirement already satisfied: charset-normalizer<4,>=2 in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from requests>=2.28->chromadb) (2.0.4)\n",
      "Requirement already satisfied: idna<4,>=2.5 in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from requests>=2.28->chromadb) (3.4)\n",
      "Requirement already satisfied: urllib3<3,>=1.21.1 in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from requests>=2.28->chromadb) (1.26.16)\n",
      "Requirement already satisfied: click>=7.0 in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from uvicorn[standard]>=0.18.3->chromadb) (8.0.4)\n",
      "Requirement already satisfied: h11>=0.8 in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from uvicorn[standard]>=0.18.3->chromadb) (0.14.0)\n",
      "Requirement already satisfied: httptools>=0.5.0 in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from uvicorn[standard]>=0.18.3->chromadb) (0.6.0)\n",
      "Requirement already satisfied: python-dotenv>=0.13 in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from uvicorn[standard]>=0.18.3->chromadb) (1.0.0)\n",
      "Requirement already satisfied: pyyaml>=5.1 in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from uvicorn[standard]>=0.18.3->chromadb) (6.0)\n",
      "Requirement already satisfied: uvloop!=0.15.0,!=0.15.1,>=0.14.0 in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from uvicorn[standard]>=0.18.3->chromadb) (0.17.0)\n",
      "Requirement already satisfied: watchfiles>=0.13 in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from uvicorn[standard]>=0.18.3->chromadb) (0.19.0)\n",
      "Requirement already satisfied: websockets>=10.4 in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from uvicorn[standard]>=0.18.3->chromadb) (11.0.3)\n",
      "Requirement already satisfied: anyio<5,>=3.4.0 in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from starlette<0.28.0,>=0.27.0->fastapi<0.100.0,>=0.95.2->chromadb) (3.5.0)\n",
      "Requirement already satisfied: humanfriendly>=9.1 in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from coloredlogs->onnxruntime>=1.14.1->chromadb) (10.0)\n",
      "Requirement already satisfied: mpmath>=0.19 in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from sympy->onnxruntime>=1.14.1->chromadb) (1.3.0)\n",
      "Requirement already satisfied: sniffio>=1.1 in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from anyio<5,>=3.4.0->starlette<0.28.0,>=0.27.0->fastapi<0.100.0,>=0.95.2->chromadb) (1.2.0)\n"
     ]
    }
   ],
   "source": [
    "!pip install chromadb"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "4d097a0f",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Requirement already satisfied: unstructured in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (0.10.12)\n",
      "Requirement already satisfied: chardet in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from unstructured) (4.0.0)\n",
      "Requirement already satisfied: filetype in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from unstructured) (1.2.0)\n",
      "Requirement already satisfied: python-magic in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from unstructured) (0.4.27)\n",
      "Requirement already satisfied: lxml in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from unstructured) (4.9.2)\n",
      "Requirement already satisfied: nltk in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from unstructured) (3.8.1)\n",
      "Requirement already satisfied: tabulate in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from unstructured) (0.8.10)\n",
      "Requirement already satisfied: requests in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from unstructured) (2.31.0)\n",
      "Requirement already satisfied: beautifulsoup4 in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from unstructured) (4.12.2)\n",
      "Requirement already satisfied: emoji in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from unstructured) (2.8.0)\n",
      "Requirement already satisfied: dataclasses-json in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from unstructured) (0.5.14)\n",
      "Requirement already satisfied: soupsieve>1.2 in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from beautifulsoup4->unstructured) (2.4)\n",
      "Requirement already satisfied: marshmallow<4.0.0,>=3.18.0 in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from dataclasses-json->unstructured) (3.20.1)\n",
      "Requirement already satisfied: typing-inspect<1,>=0.4.0 in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from dataclasses-json->unstructured) (0.9.0)\n",
      "Requirement already satisfied: click in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from nltk->unstructured) (8.0.4)\n",
      "Requirement already satisfied: joblib in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from nltk->unstructured) (1.2.0)\n",
      "Requirement already satisfied: regex>=2021.8.3 in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from nltk->unstructured) (2022.7.9)\n",
      "Requirement already satisfied: tqdm in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from nltk->unstructured) (4.65.0)\n",
      "Requirement already satisfied: charset-normalizer<4,>=2 in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from requests->unstructured) (2.0.4)\n",
      "Requirement already satisfied: idna<4,>=2.5 in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from requests->unstructured) (3.4)\n",
      "Requirement already satisfied: urllib3<3,>=1.21.1 in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from requests->unstructured) (1.26.16)\n",
      "Requirement already satisfied: certifi>=2017.4.17 in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from requests->unstructured) (2023.7.22)\n",
      "Requirement already satisfied: packaging>=17.0 in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from marshmallow<4.0.0,>=3.18.0->dataclasses-json->unstructured) (23.0)\n",
      "Requirement already satisfied: mypy-extensions>=0.3.0 in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from typing-inspect<1,>=0.4.0->dataclasses-json->unstructured) (0.4.3)\n",
      "Requirement already satisfied: typing-extensions>=3.7.4 in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (from typing-inspect<1,>=0.4.0->dataclasses-json->unstructured) (4.7.1)\n"
     ]
    }
   ],
   "source": [
    "! pip install unstructured"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "042564ea",
   "metadata": {},
   "source": [
    "# 加载文档 （Document Loader）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "8b596ba3",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.document_loaders import DirectoryLoader\n",
    "loader = DirectoryLoader('./', glob=\"spotmax_intro.txt\")\n",
    "docs = loader.load()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "d651fca8",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Requirement already satisfied: pypdf in /Users/mbj0593/anaconda3/lib/python3.11/site-packages (3.15.5)\r\n"
     ]
    }
   ],
   "source": [
    "!pip install pypdf"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "250281c4",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.document_loaders import PyPDFLoader\n",
    "\n",
    "loader = PyPDFLoader(\"Spotmax_intro_cn_2020.pdf\")\n",
    "docs = loader.load()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f7efce11",
   "metadata": {},
   "source": [
    "# 切割文档\n",
    "这个文本分割器是通用文本的推荐分割器。它由一个字符列表参数化。它会按顺序尝试在这些字符上进行分割，直到分块足够小。默认列表是[\"\\n\\n\", \"\\n\", \" \", “\"]。这样做的效果是尽可能地保持所有段落（然后是句子，然后是单词）在一起。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "c3ffc86b",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.text_splitter import RecursiveCharacterTextSplitter\n",
    "text_splitter = RecursiveCharacterTextSplitter(\n",
    "    chunk_size = 200,\n",
    "    chunk_overlap = 10\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "4ea0099e",
   "metadata": {},
   "outputs": [],
   "source": [
    "splits = text_splitter.split_documents(docs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "9f1f001f",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "page_content='SpotMax 打破成本约束，释放云端创造⼒ 构建⼤规模云端系统的挑战 云计算平台“按需获取”的特性使得⽤户可以随时获取所需计算资源，实现计算资源与业务规模的动态匹配。云计算时代计算资源已不再是构建⼤规模系统的瓶颈，多数情况下成本成为了企业在构建⼤规模应⽤时的最⼤挑战。 什么是 SpotMax?' metadata={'source': 'Spotmax_intro_cn_2020.pdf', 'page': 0}\n"
     ]
    }
   ],
   "source": [
    "print(splits[0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "b86b82b3",
   "metadata": {},
   "outputs": [],
   "source": [
    "persist_directory = 'data/'\n",
    "!rm -rf ./data  "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "16d58945",
   "metadata": {},
   "source": [
    "# 将数据存入向量数据库"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "bbe56e8a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "16\n"
     ]
    }
   ],
   "source": [
    "from langchain.embeddings.openai import OpenAIEmbeddings\n",
    "from langchain.vectorstores import Chroma\n",
    "# embedding = OpenAIEmbeddings() #如何直接调用OpenAI的 GPT 服务\n",
    "embedding = OpenAIEmbeddings(deployment=embedding_deployment) #通过Azure的OpenAI GPT服务\n",
    "vectordb = Chroma.from_documents(\n",
    "    documents=splits,\n",
    "    collection_name=\"spotmax\",\n",
    "    embedding=embedding,\n",
    "    persist_directory=persist_directory\n",
    ")\n",
    "vectordb.persist()\n",
    "print(vectordb._collection.count())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "085d90ce",
   "metadata": {},
   "outputs": [],
   "source": [
    "docs = vectordb.similarity_search(\"如何提高可用性\",k=2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "50363a78",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Document(page_content='降低中断带来的服务器容量变化带来的服务能⼒影响，实现服务及数据的提前迁移。 4.MaxGroup将根据现货价格和终⽌率的变化持续优化集群结构。  5.⽀持智能的动态负载均衡，由于集群为多机型混合，不同机型的处理能⼒有差异，智能的动态负载均衡将实现按处理能⼒的负载分配，实现集群资源利⽤的最⼤化。', metadata={'page': 1, 'source': 'Spotmax_intro_cn_2020.pdf'})"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "docs[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b6cf975a",
   "metadata": {},
   "source": [
    "# 利用向量数据库进行QA\n",
    "\n",
    "https://github.com/langchain-ai/langchain/blob/master/libs/langchain/langchain/chains/retrieval_qa/prompt.py"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "4c63279f",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.chains import RetrievalQA\n",
    "from langchain.chat_models import AzureChatOpenAI\n",
    "# from langchain.chat_models import ChatOpenAI #直接访问OpenAI的GPT服务\n",
    "\n",
    "#llm = ChatOpenAI(model_name=\"gpt-4\", temperature=0) #直接访问OpenAI的GPT服务\n",
    "llm = AzureChatOpenAI(deployment_name = deployment, model_name=model, temperature=0.7, max_tokens=1000) #通过Azure的OpenAI服务\n",
    "retriever=vectordb.as_retriever(\n",
    "    search_type=\"mmr\", search_kwargs={\"k\": 3}\n",
    "    #search_type=\"similarity\", search_kwargs={\"k\": 3}\n",
    ")\n",
    "qa = RetrievalQA.from_chain_type(llm=llm, chain_type=\"refine\", retriever=retriever,\n",
    "                                 return_source_documents=False, verbose=True)\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "eb024f75",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new RetrievalQA chain...\u001b[0m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Number of requested results 20 is greater than number of elements in index 16, updating n_results = 16\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n",
      "SpotMax是一个利用弹性计算资源进行云端系统成本优化的体系（包括相关产品及解决方案）。SpotMax旨在帮助用户使用云平台提供的弹性资源（如：AWS Spot Instance）在保证系统可用性，甚至获得更高可用性的前提下，实现成本的最大化节省。SpotMax来自于Mobvista降低成本的成功实践。\n"
     ]
    }
   ],
   "source": [
    "result = qa({\"query\": \"什么是SpotMax?\"})\n",
    "print(result[\"result\"])\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "ca5c2d35",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new RetrievalQA chain...\u001b[0m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Number of requested results 20 is greater than number of elements in index 16, updating n_results = 16\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n",
      "SpotMax通过使用云服务供应商的折扣实例（如AWS的Spot Instance）来降低成本。这些实例的价格通常远低于预留实例或按需实例，从而大大减少了云计算成本。SpotMax还具有弹性扩展和智能切换的功能，能够在折扣实例不可用时自动切换到其他类型的实例，无缝保障服务的连续性。使用SpotMax，用户能在保证稳定运行的同时，实现成本的有效降低。\n"
     ]
    }
   ],
   "source": [
    "result = qa({\"query\": \"SpotMax如何降低成本\"})\n",
    "print(result[\"result\"])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c0b4b325",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
